package system

import (
	consts2 "MoSkeleton/config/consts"
	"MoSkeleton/framework/core/consts"
	"MoSkeleton/framework/core/dto/response"
	"MoSkeleton/framework/core/models"
	"MoSkeleton/framework/core/moerrors"
	"MoSkeleton/framework/mo_gorm"
	"MoSkeleton/framework/utils"
	"MoSkeleton/global"
	utils2 "MoSkeleton/global/utils"
	"MoSkeleton/models/system"
	"MoSkeleton/services/base"
	"MoSkeleton/services/common"
	s1 "MoSkeleton/web/pogos/request/system"
	system2 "MoSkeleton/web/pogos/response/system"
	"bytes"
	"fmt"
	mapset "github.com/deckarep/golang-set/v2"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/golang-jwt/jwt/v5"
	"github.com/samber/lo"
	"gorm.io/gorm"
	"mime/multipart"
	"strconv"
	"strings"
)

const allocateUserSelectFileds = "u.id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.created_at"

type SysUserService struct {
	base.BaseService
}

func (s *SysUserService) GetUserPage(c *gin.Context, userReq *s1.SysUserPageReq) (*response.PageResult, error) {
	db := s.getUserListVo(userReq)
	itemsResp := make([]*system2.SysUserItemResp, 0)
	var total int64
	s.QueryDataScope(c, db)
	s.SetDataScopeUserAlias(db, "u.")
	s.SetDataScopeDeptAlias(db, "d.")

	defer func() {
		mo_gorm.ResetDataScopeCount(db)
	}()
	if err := db.Count(&total).Offset(userReq.Offset()).Limit(userReq.Limit()).Find(&itemsResp).Error; err != nil {
		return nil, err
	}
	pageResult := response.NewFromPageInfoAndData(&userReq.PageInfo, &itemsResp, total)
	return pageResult, nil
}

func (s *SysUserService) Export(userReq *s1.SysUserPageReq) (*bytes.Buffer, error) {
	db := s.getUserListVo(userReq)
	itemsResp := make([]*system2.ExportUserItemResp, 0)
	err := db.Find(&itemsResp).Error
	if err != nil {
		return nil, err
	}
	titles := []string{"用户编号", "用户名称", "用户昵称", "用户邮箱", "手机号码", "用户性别", "状态", "最后登录IP", "最后登录时间", "部门", "部门负责人"}
	exportFile := utils.NewExportExcelFile()
	return exportFile.Export(consts2.Excel_Sheet_User, &titles, func(row, col int, colTitle string) (value any, ok bool, err error) {
		if len(itemsResp) <= row {
			return "", false, nil
		}
		itemResp := itemsResp[row]
		switch col {
		case 0:
			return "'" + strconv.FormatUint(itemResp.ID, 10), true, nil
		case 1:
			return itemResp.UserName, true, nil
		case 2:
			return itemResp.NickName, true, nil
		case 3:
			return itemResp.Email, true, nil
		case 4:
			return itemResp.Phonenumber, true, nil
		case 5:
			if itemResp.Sex == consts2.U_Sex_Male {
				return consts2.U_Sex_Male_Label, true, nil
			} else if itemResp.Sex == consts2.U_Sex_Female {
				return consts2.U_Sex_Female_Label, true, nil
			} else {
				return consts2.U_Sex_Secret_Label, true, nil
			}
		case 6:
			if itemResp.Status == consts2.U_NORMAL {
				return "正常", true, nil
			} else {
				return "停用", true, nil
			}
		case 7:
			return itemResp.LoginIp, true, nil
		case 8:
			if itemResp.LoginDate != nil {
				return itemResp.LoginDate.Format("2006-01-02 15:04:05"), true, nil
			} else {
				return "", true, nil
			}
		case 9:
			return itemResp.DeptName, true, nil
		case 10:
			return itemResp.Leader, true, nil
		}
		return "", false, nil
	})
}

func (s *SysUserService) ImportTemplate() (*bytes.Buffer, error) {
	titles := []string{"部门编号", "用户名称", "用户昵称", "用户邮箱", "手机号码", "用户性别", "帐号状态"}
	exportFile := utils.NewExportExcelFile()
	return exportFile.Export(consts2.Excel_Sheet_User, &titles, nil)
}

func (s *SysUserService) ImportUser(c *gin.Context, fileHeader *multipart.FileHeader, updateSupport bool, operUsername string) (string, error) {
	importDataItemsReq, err := s.dataItemsFromImportUser(fileHeader)
	if err != nil {
		return "", err
	}
	return s.importUserData(c, importDataItemsReq, updateSupport, operUsername)
}
func (s *SysUserService) GetUserDetailById(c *gin.Context, id *uint64) (*system2.SysUserDetailResp, error) {
	//DONE data scope
	if id != nil {
		if err := s.CheckUserDataScope(c, *id); err != nil {
			return nil, err
		}
	}
	userDetailResp := system2.SysUserDetailResp{}
	//DONE roles, posts
	posts, err := sysPostService.GetPostAll()
	if err != nil {
		return nil, err
	}
	roles, err := sysRoleService.GetRolesByUserDetailId(nil)
	if err != nil {
		return nil, err
	}
	userDetailResp.Roles = &roles
	userDetailResp.Posts = posts
	if id != nil {
		detailItemResp, err := s.GetUserById(*id)
		if err != nil {
			return nil, err
		}
		userDetailResp.User = detailItemResp
		postIds, err := new(system.SysDept).GetDeptIdsByUserId(*id)
		if err != nil {
			return nil, err
		}
		userDetailResp.PostIds = *utils.Uint64sToStrs(&postIds)

		roleIds := lo.Map(detailItemResp.Roles, func(item *system2.SysUserDetailRoleItemResp, _ int) uint64 {
			return item.ID
		})
		userDetailResp.RoleIds = *utils.Uint64sToStrs(&roleIds)
	}
	return &userDetailResp, nil
}

func (s *SysUserService) GetUserById(id uint64) (*system2.SysUserDetailItemResp, error) {
	selectFields := "u.id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.created_at, u.remark"
	db := base.BaseDb.Select(selectFields).Table("sys_user u")
	db.Where("u.id = ?", id)
	sysUser := system2.SysUserDetailItemResp{}
	if err := db.First(&sysUser).Error; err != nil {
		return nil, err
	}
	dept, err := sysDeptService.GetDeptByUserDetailId(id)
	if err != nil {
		return nil, err
	}
	sysUser.Dept = dept
	roles, err := sysRoleService.GetRolesByUserDetailId(&id)
	if err != nil {
		return nil, err
	}
	sysUser.Roles = roles
	return &sysUser, nil
}

func (s *SysUserService) GetLoginUserInfo(id uint64) (*system2.SysUserInfoResp, error) {
	sysUser, err := s.GetDetail(id)
	if err != nil {
		return nil, err
	}
	var roleKeys, menuPerms *mapset.Set[string]
	if roleKeys, err = sysRoleService.GetRoleKeysByUserId(id); err != nil {
		return nil, err
	}
	if menuPerms, err = sysMenuService.GetMenuPermsByUserId(id); err != nil {
		return nil, err
	}
	sysUserInfoResp := system2.SysUserInfoResp{
		User:        sysUser,
		Roles:       roleKeys,
		Permissions: menuPerms,
	}
	return &sysUserInfoResp, nil
}

func (s *SysUserService) GetDetail(id uint64) (*system2.SysUserItemResp, error) {
	sysUser := system.SysUser{
		MoModel: models.MoModel{
			ID: id,
		},
	}
	itemResp := system2.SysUserItemResp{}
	result := base.BaseDb.First(&sysUser)

	if err := utils.CopyStruct(&itemResp, &sysUser); err != nil {
		return nil, err
	}

	return &itemResp, result.Error
}

/*
检测部门下是否有用户
select count(1) from sys_user where dept_id = #{deptId} and del_flag = '0'
*/
func (d *SysUserService) CheckDeptExistsUser(deptId uint64) (bool, error) {
	var count int64
	if err := base.BaseDb.Model(&system.SysUser{}).Where("dept_id = ?  and del_flag =?", deptId, 0).Count(&count).Error; err != nil {
		return false, err
	}
	return count > 0, nil
}

func (s *SysUserService) CheckUserDataScope(c *gin.Context, id uint64) error {
	if system.IsUserAdmin(id) {
		return nil
	}
	userReq := new(s1.SysUserPageReq)
	userReq.ID = id
	pageResult, err := s.GetUserPage(c, userReq)
	if err != nil {
		return err
	}
	if pageResult.Total == 0 {
		return moerrors.NewValidateError(consts.DataScopeLimitedCode, "没有权限访问用户数据！")
	}
	return nil
}

/*
select distinct u.id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.created_at

	    from sys_user u
			 left join sys_dept d on u.dept_id = d.id
			 left join sys_user_role ur on u.id = ur.user_id
			 left join sys_role r on r.id = ur.role_id
	    where u.del_flag = '0' and r.id = #{roleId}
	    <if test="userName != null and userName != ''">
			AND u.user_name like concat('%', #{userName}, '%')
		</if>
		<if test="phonenumber != null and phonenumber != ''">
			AND u.phonenumber like concat('%', #{phonenumber}, '%')
		</if>
		<!-- 数据范围过滤 -->
		${params.dataScope}
*/
func (s *SysUserService) GetAllocatedListPage(c *gin.Context, userItem *s1.RoleAllocatedUserItemReq) (*response.PageResult, error) {

	db := base.BaseDb.Table("sys_user u")
	db.Joins("left join sys_dept d on u.dept_id = d.id")
	db.Joins("left join sys_user_role ur on u.id = ur.user_id")
	db.Joins("left join sys_role r on r.id = ur.role_id")
	db.Where("u.del_flag = ? and r.id = ?", "0", userItem.RoleId)
	if userItem.UserName != "" {
		db.Where("u.user_name like ?", "%"+userItem.UserName+"%")
	}
	if userItem.Phonenumber != "" {
		db.Where("u.phonenumber like ?", "%"+userItem.Phonenumber+"%")
	}
	pageResult := response.NewFromPageInfo(&userItem.PageInfo)
	itemsResp := make([]*system2.SysUserDeptItemResp, 0)
	s.QueryDataScope(c, db)
	s.SetDataScopeUserAlias(db, "u.")
	s.SetDataScopeDeptAlias(db, "d.")

	defer func() {
		mo_gorm.ResetDataScopeCount(db)
	}()
	var count int64
	db.Select("COUNT(DISTINCT " + allocateUserSelectFileds + ")").Count(&count)
	db.Select("DISTINCT " + allocateUserSelectFileds)
	result := db.Offset(userItem.Offset()).Limit(userItem.Limit()).Find(&itemsResp)
	pageResult.Total = count
	pageResult.Rows = itemsResp
	return pageResult, result.Error
}

/*
select distinct u.id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.created_at

	    from sys_user u
			 left join sys_dept d on u.dept_id = d.id
			 left join sys_user_role ur on u.id = ur.user_id
			 left join sys_role r on r.id = ur.role_id
	    where u.del_flag = '0' and (r.id != #{roleId} or r.id IS NULL)
	    and u.id not in (select u.id from sys_user u inner join sys_user_role ur on u.id = ur.user_id and ur.role_id = #{roleId})
	    <if test="userName != null and userName != ''">
			AND u.user_name like concat('%', #{userName}, '%')
		</if>
		<if test="phonenumber != null and phonenumber != ''">
			AND u.phonenumber like concat('%', #{phonenumber}, '%')
		</if>
		<!-- 数据范围过滤 -->
		${params.dataScope}
*/
func (s *SysUserService) GetUnallocatedListPage(c *gin.Context, userItem *s1.RoleAllocatedUserItemReq) (*response.PageResult, error) {
	db := base.BaseDb.Table("sys_user u")
	db.Joins("left join sys_dept d on u.dept_id = d.id")
	db.Joins("left join sys_user_role ur on u.id = ur.user_id")
	db.Joins("left join sys_role r on r.id = ur.role_id")
	db.Where("u.del_flag = ? and (r.id != ? or r.id IS NULL)", "0", userItem.RoleId)
	db.Where("u.id not in (select u.id from sys_user u inner join sys_user_role ur on u.id = ur.user_id and ur.role_id = ?)", userItem.RoleId)
	if userItem.UserName != "" {
		db.Where("u.user_name like ?", "%"+userItem.UserName+"%")
	}
	if userItem.Phonenumber != "" {
		db.Where("u.phonenumber like ?", "%"+userItem.Phonenumber+"%")
	}

	pageResult := response.NewFromPageInfo(&userItem.PageInfo)
	itemsResp := make([]*system2.SysUserDeptItemResp, 0)
	s.QueryDataScope(c, db)
	s.SetDataScopeUserAlias(db, "u.")
	s.SetDataScopeDeptAlias(db, "d.")

	defer func() {
		mo_gorm.ResetDataScopeCount(db)
	}()
	var count int64
	db.Select("COUNT(DISTINCT " + allocateUserSelectFileds + ")").Count(&count)
	db.Select("DISTINCT " + allocateUserSelectFileds)
	result := db.Offset(userItem.Offset()).Limit(userItem.Limit()).Find(&itemsResp)
	pageResult.Total = count
	pageResult.Rows = itemsResp
	return pageResult, result.Error
}

func (s *SysUserService) AddUser(c *gin.Context, userAddReq *s1.SysUserAddReq) (bool, error) {
	//DONE data scope
	var deptId uint64
	if userAddReq.DeptId != nil {
		deptId = *userAddReq.DeptId
	}
	if err := sysDeptService.CheckDeptDataScope(c, deptId); err != nil {
		return false, err
	}
	roleIds := utils.StrsToUint64s(&userAddReq.RoleIds)
	if err := sysRoleService.CheckRoleDataScope(c, *roleIds...); err != nil {
		return false, err
	}
	sysUser := system.SysUser{}

	if err := utils.CopyStruct(&sysUser, userAddReq); err != nil {
		return false, err
	}
	var err error
	sysUser.Password, err = utils.DecryptPasswordFromFront(sysUser.Password)
	if err != nil {
		return false, err
	}
	if unique, err := sysUser.CheckUsernameUnique(); err != nil {
		return false, err
	} else if !unique {
		return false, moerrors.NewValidateError(consts.CommCreatFailCode, "用户名已存在")
	}
	if unique, err := sysUser.CheckPhoneUnique(); err != nil {
		return false, err
	} else if !unique {
		return false, moerrors.NewValidateError(consts.CommCreatFailCode, "手机号码已存在")
	}
	if unique, err := sysUser.CheckEmailUnique(); err != nil {
		return false, err
	} else if !unique {
		return false, moerrors.NewValidateError(consts.CommCreatFailCode, "邮箱已存在")
	}
	sysUser.DelFlag = consts2.U_NORMAL
	sysUser.GenPwdForNew(sysUser.Password)

	err = base.BaseDb.Transaction(func(tx *gorm.DB) error {
		result := s.GetDb(tx).Create(&sysUser)
		if result.Error != nil {
			return moerrors.NewValidateError(consts.CommCreatFailCode, "创建失败")
		}
		if _, err := (&system.SysUserPost{}).AddBatchByUser(tx, sysUser.ID, utils.StrsToUint64s(&userAddReq.PostIds)); err != nil {
			return err
		}
		if _, err := (&system.SysUserRole{}).AddUserRoleIds(tx, sysUser.ID, utils.StrsToUint64s(&userAddReq.RoleIds)); err != nil {
			return err
		}
		return nil
	})
	return true, err
}

func (s *SysUserService) UpdateUser(c *gin.Context, userUpdateReq *s1.SysUserUpdateReq) (bool, error) {
	sysUser := system.SysUser{}
	if err := s.validateUpdateUser(c, &sysUser, userUpdateReq); err != nil {
		return false, err
	}
	err := base.BaseDb.Transaction(func(tx *gorm.DB) error {
		if _, err := new(system.SysUserRole).DeleteByUserId(tx, sysUser.ID); err != nil {
			return err
		}
		if _, err := new(system.SysUserPost).DeleteByUserIds(tx, &[]uint64{sysUser.ID}); err != nil {
			return err
		}
		if _, err := (&system.SysUserPost{}).AddBatchByUser(tx, sysUser.ID, utils.StrsToUint64s(&userUpdateReq.PostIds)); err != nil {
			return err
		}
		if _, err := (&system.SysUserRole{}).AddUserRoleIds(tx, sysUser.ID, utils.StrsToUint64s(&userUpdateReq.RoleIds)); err != nil {
			return err
		}
		result := tx.Updates(&sysUser)
		if result.Error != nil {
			return result.Error
		}
		return nil
	})
	if err != nil {
		return false, err
	}
	return true, err
}

func (s *SysUserService) UpdateAuthRole(c *gin.Context, updateAuthRoleReq *s1.UpdateAuthRoleReq) (bool, error) {
	//DONE data scope
	if err := s.CheckUserDataScope(c, updateAuthRoleReq.ID); err != nil {
		return false, err
	}
	roleIdsStr := strings.Split(updateAuthRoleReq.RoleIds, ",")
	roleIds := utils.StrsToUint64s(&roleIdsStr)
	if err := sysRoleService.CheckRoleDataScope(c, *roleIds...); err != nil {
		return false, err
	}
	sysUserRole := new(system.SysUserRole)
	err := base.BaseDb.Transaction(func(tx *gorm.DB) error {
		if _, err := sysUserRole.DeleteByUserIds(tx, &[]uint64{updateAuthRoleReq.ID}); err != nil {
			return err
		}
		_, err := sysUserRole.AddUserRoleIds(tx, updateAuthRoleReq.ID, roleIds)
		return err
	})
	return err == nil, err
}

func (s *SysUserService) ResetPassword(c *gin.Context, resetPwdReq *s1.ResetPasswordReq) (bool, error) {
	sysUser := system.SysUser{}
	sysUser.ID = resetPwdReq.ID
	//if sysUser.IsAdmin() {
	//	return false, moerrors.NewValidateError(consts.CommUpdateFailCode, "不允许重置超级管理员密码")
	//}
	if err := s.CheckUserDataScope(c, resetPwdReq.ID); err != nil {
		return false, err
	}
	result := base.BaseDb.Select("id, salt").First(&sysUser)
	if result.Error != nil {
		return false, moerrors.NewValidateError(consts.CommSelectFailCode, "用户不存在")
	}
	if srcPassword, err := utils.DecryptPasswordFromFront(resetPwdReq.Password); err != nil {
		return false, err
	} else {
		sysUser.Password = utils.HashPasswd(srcPassword, sysUser.Salt)
	}
	return true, base.BaseDb.Model(&sysUser).Updates(map[string]interface{}{"password": sysUser.Password}).Error
}

func (s *SysUserService) DeleteUsers(c *gin.Context, ids *[]uint64) (bool, error) {
	if system.HasAdmin(ids) {
		return false, moerrors.NewValidateError(consts.CommDeleteFailCode, "不允许删除超级管理员")
	}
	//DONE data scope
	for _, id := range *ids {
		if err := s.CheckUserDataScope(c, id); err != nil {
			return false, err
		}
	}
	err := base.BaseDb.Transaction(func(tx *gorm.DB) error {
		if _, err := new(system.SysUserPost).DeleteByUserIds(tx, ids); err != nil {
			return err
		}
		if _, err := new(system.SysUserRole).DeleteByUserIds(tx, ids); err != nil {
			return err
		}
		if _, err := new(system.SysUser).DeleteByIds(tx, ids); err != nil {
			return err
		}
		return nil
	})
	return err != nil, err
}

func (a *SysUserService) MakeUserOnline(userId uint64, onlineUser *system2.OnlineUserResp, expiresAt *jwt.NumericDate) (*system2.SysUserDetailItemResp, error) {
	detailItemResp, err := a.GetUserById(userId)
	if err != nil {
		return nil, err
	}
	onlineUser.User = detailItemResp
	onlineUser.Permissions, err = sysMenuService.GetMenuPermsByUserId(userId)
	if err != nil {
		return nil, err
	}
	err = utils2.SetRedisOnlineUser(userId, onlineUser, expiresAt.Unix())
	if err != nil {
		return nil, err
	}
	return detailItemResp, nil
}

func (s *SysUserService) GetProfile(userId uint64) (*system2.UserProfileResp, error) {
	onlineUser, err := utils2.GetRedisOnlineUser(userId)
	if err != nil {
		return nil, err
	}
	roleNames, err := sysRoleService.GetRoleNamesByUserId(userId)
	if err != nil {
		return nil, err
	}
	postNames, err := sysPostService.GetPostNamesByUserId(userId)
	if err != nil {
		return nil, err
	}
	return &system2.UserProfileResp{
		User:      onlineUser.User,
		PostGroup: strings.Join(postNames, ","),
		RoleGroup: strings.Join(roleNames, ","),
	}, nil
}
func (s *SysUserService) UpdateProfile(updateProfileReq *s1.UpdateProfileReq) error {
	if err := base.BaseDb.Model(&system.SysUser{}).Where("id = ?", updateProfileReq.ID).Updates(map[string]interface{}{
		"nick_name":   updateProfileReq.NickName,
		"email":       updateProfileReq.Email,
		"phonenumber": updateProfileReq.Phonenumber,
		"sex":         updateProfileReq.Sex,
	}).Error; err != nil {
		return err
	}
	onlineUser, err := utils2.GetRedisOnlineUser(updateProfileReq.ID)
	if err != nil {
		return err
	}
	onlineUser.User.NickName = updateProfileReq.NickName
	onlineUser.User.Email = updateProfileReq.Email
	onlineUser.User.Phonenumber = updateProfileReq.Phonenumber
	onlineUser.User.Sex = updateProfileReq.Sex
	if err := utils2.SetRedisOnlineUser(updateProfileReq.ID, onlineUser, 0); err != nil {
		return err
	}
	return nil
}

func (s *SysUserService) UpdateProfilePassword(updatePasswordReq *s1.UpdatePasswordReq) error {
	sysUser := system.SysUser{}
	ok, err := sysUser.GetWithPasswordById(updatePasswordReq.ID)
	if err != nil {
		return err
	} else if !ok {
		global.MoLogger.Info("用户不存在")
		return moerrors.NewValidateError(consts.CommSelectFailCode, "用户名或密码错误")
	}
	ok = utils.PasswordValidateFromFront(updatePasswordReq.OldPassword, sysUser.Password, sysUser.Salt)
	if !ok {
		return moerrors.NewValidateError(consts.CommSelectFailCode, "旧密码错误")
	}
	newPassword, err := utils.DecryptPasswordFromFront(updatePasswordReq.NewPassword)
	if err != nil {
		return err
	}
	oldPassword, err := utils.DecryptPasswordFromFront(updatePasswordReq.OldPassword)
	if err != nil {
		return err
	}
	if newPassword == oldPassword {
		return moerrors.NewValidateError(consts.CommSelectFailCode, "新密码与旧密码相同")
	}
	sysUser.Password = utils.HashPasswd(newPassword, sysUser.Salt)
	return base.BaseDb.Model(&sysUser).Updates(map[string]interface{}{"password": sysUser.Password}).Error
}

func (s *SysUserService) UpdateProfileAvatar(id uint64, file *multipart.FileHeader) (string, error) {
	onlineUser, err := utils2.GetRedisOnlineUser(id)
	if err != nil {
		return "", err
	}
	uploadBasePath := common.CommonGroupInst.CommonServiceInst.GetUploadBasePath()
	browserFilename, err := common.CommonGroupInst.CommonServiceInst.UploadFileWithExtensions(uploadBasePath, "avatars", file, &consts.IMAGE_EXTENSION)
	if err != nil {
		return "", err
	}
	onlineUser.User.Avatar = browserFilename
	if err := base.BaseDb.Model(&system.SysUser{}).Where("id = ?", id).Updates(map[string]interface{}{
		"avatar": browserFilename,
	}).Error; err != nil {
		return "", err
	}
	if err := utils2.SetRedisOnlineUser(id, onlineUser, 0); err != nil {
		return "", err
	}
	return browserFilename, err
}

func (s *SysUserService) ChangeStatus(c *gin.Context, req *s1.ChangeUserStatusReq) (bool, error) {
	sysUser := system.SysUser{}
	sysUser.ID = req.ID
	if sysUser.IsAdmin() {
		return false, moerrors.NewValidateError(consts.CommSelectFailCode, "不允许修改超级管理员")
	}

	//DONE data scope
	if err := s.CheckUserDataScope(c, sysUser.ID); err != nil {
		return false, err
	}
	result := s.GetDb(nil).Model(&sysUser).Updates(map[string]interface{}{"status": req.Status, "updated_by": req.UpdatedBy})
	return result.RowsAffected > 0, result.Error
}

func (s *SysUserService) validateUpdateUser(c *gin.Context, sysUser *system.SysUser, userUpdateReq *s1.SysUserUpdateReq) error {

	if err := utils.CopyStruct(sysUser, userUpdateReq); err != nil {
		return err
	}
	if sysUser.IsAdmin() {
		return moerrors.NewValidateError(consts.CommCreatFailCode, "不允许修改超级管理员")
	}
	//DONE datascope
	if err := s.CheckUserDataScope(c, sysUser.ID); err != nil {
		return err
	}
	var deptId uint64
	if userUpdateReq.DeptId != nil {
		deptId = *userUpdateReq.DeptId
	}
	if err := sysDeptService.CheckDeptDataScope(c, deptId); err != nil {
		return err
	}
	roleIds := utils.StrsToUint64s(&userUpdateReq.RoleIds)
	if err := sysRoleService.CheckRoleDataScope(c, *roleIds...); err != nil {
		return err
	}
	if unique, err := sysUser.CheckUsernameUnique(); err != nil {
		return err
	} else if !unique {
		return moerrors.NewValidateError(consts.CommCreatFailCode, "用户名已存在")
	}
	if unique, err := sysUser.CheckPhoneUnique(); err != nil {
		return err
	} else if !unique {
		return moerrors.NewValidateError(consts.CommCreatFailCode, "手机号码已存在")
	}
	if unique, err := sysUser.CheckEmailUnique(); err != nil {
		return err
	} else if !unique {
		return moerrors.NewValidateError(consts.CommCreatFailCode, "邮箱已存在")
	}
	return nil
}

/*
select u.id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader
from sys_user u

	left join sys_dept d on u.dept_id = d.id
	where u.del_flag = '0'
	<if test="userId != null and userId != 0">
		AND u.id = #{userId}
	</if>
	<if test="userName != null and userName != ''">
		AND u.user_name like concat('%', #{userName}, '%')
	</if>
	<if test="status != null and status != ''">
		AND u.status = #{status}
	</if>
	<if test="phonenumber != null and phonenumber != ''">
		AND u.phonenumber like concat('%', #{phonenumber}, '%')
	</if>
	<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
		AND date_format(u.create_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')
	</if>
	<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
		AND date_format(u.create_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
	</if>
	<if test="deptId != null and deptId != 0">
		AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
	</if>
	<!-- 数据范围过滤 -->
	${params.dataScope}
*/
func (s *SysUserService) getUserListVo(userReq *s1.SysUserPageReq) *gorm.DB {
	selectedFields := "u.id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.created_by, u.created_at, u.remark, d.dept_name, d.leader"
	db := base.BaseDb.Table("sys_user u").Select(selectedFields)
	db.Joins("left join sys_dept d on u.dept_id = d.id").Where("u.del_flag = ?", "0")
	if userReq.ID != 0 {
		db.Where("u.id = ?", userReq.ID)
	}
	if userReq.UserName != "" {
		db.Where("u.user_name like ?", "%"+userReq.UserName+"%")
	}
	if userReq.Status != "" {
		db.Where("u.status = ?", userReq.Status)
	}
	if userReq.Phonenumber != "" {
		db.Where("u.phonenumber like ?", "%"+userReq.Phonenumber+"%")
	}
	if userReq.DeptId != 0 {
		db.Where("u.dept_id = ? or u.dept_id in (select t.id from sys_dept t where find_in_set(?, t.ancestors))", userReq.DeptId, userReq.DeptId)
	}
	beginTime, ok := userReq.GetParamValue("beginTime")
	if ok && beginTime != "" {
		if beginTime = userReq.FormatBeginTime(beginTime); beginTime != "" {
			db.Where("created_at >= ?", beginTime)
		}
	}
	endTime, ok := userReq.GetParamValue("endTime")
	if ok && endTime != "" {
		if endTime = userReq.FormatEndTime(endTime); endTime != "" {
			db.Where("created_at <= ?", endTime)
		}
	}
	return db
}

func (s *SysUserService) importUserData(c *gin.Context, importDataItemsReq *[]s1.UserImportDataItemReq, updateSupport bool, operUsername string) (string, error) {
	if len(*importDataItemsReq) == 0 {
		return "", moerrors.NewValidateError(consts.FilesUploadFailCode, "上传用户为空")
	}
	successNum := 0
	failNum := 0
	failMsg := ""
	successMsg := ""
	sysUser := system.SysUser{}
	var initPassword string
	for _, item := range *importDataItemsReq {
		id, err := sysUser.GetIdByUsername(item.UserName)
		if err != nil {
			failNum++
			failMsg += "<br/>" + item.UserName + ":" + err.Error()
		} else if id == 0 {
			err = binding.Validator.ValidateStruct(*importDataItemsReq)
			if err != nil {
				failNum++
				failMsg += "<br/>" + item.UserName + ":" + err.Error()
				continue
			}
			//DONE data scope
			if err := sysDeptService.CheckDeptDataScope(c, item.DeptId); err != nil {
				failNum++
				failMsg += "<br/>" + item.UserName + ":" + err.Error()
				continue
			}
			if initPassword == "" {
				configItem, err := sysConfigService.GetByConfigKey(consts2.ConfigKey_InitPasswd)
				if err != nil {
					failNum++
					failMsg += "<br/>" + item.UserName + ": " + err.Error()
					continue
				}
				initPassword = configItem.ConfigValue
			}

			_ = utils.CopyStruct(&sysUser, &item)
			sysUser.DeptId = &item.DeptId
			sysUser.GenPwdForNew(initPassword)
			sysUser.CreatedBy = operUsername
			sysUser.UpdatedBy = operUsername
			sysUser.DelFlag = consts2.U_NORMAL
			if item.Status == consts2.U_DISABLE_LABEL {
				sysUser.Status = consts2.U_DISABLE
			} else {
				sysUser.Status = consts2.U_NORMAL
			}
			if item.Sex == consts2.U_Sex_Male_Label {
				sysUser.Sex.String = consts2.U_Sex_Male
			} else if item.Sex == consts2.U_Sex_Female_Label {
				sysUser.Sex.String = consts2.U_Sex_Female
			} else {
				sysUser.Sex.String = consts2.U_Sex_Secret
			}
			result := base.BaseDb.Create(&sysUser)
			if result.Error != nil {
				failNum++
				failMsg += "<br/>" + item.UserName + ":" + result.Error.Error()
				continue
			}
			successNum++
			successMsg += "<br/>" + item.UserName + ": 导入成功"
		} else if id > 0 && updateSupport {
			sysUser.ID = id
			//校验req 的字段绑定是否合规
			err = binding.Validator.ValidateStruct(*importDataItemsReq)
			if err != nil {
				failNum++
				failMsg += "<br/>" + item.UserName + ":" + err.Error()
				continue
			}
			if system.IsUserAdmin(id) {
				failNum++
				failMsg += "<br/>" + item.UserName + ": 管理员不允许修改"
				continue
			}
			//DONE data scope
			if err := s.CheckUserDataScope(c, id); err != nil {
				failNum++
				failMsg += "<br/>" + item.UserName + ":" + err.Error()
				continue
			}
			if err := sysDeptService.CheckDeptDataScope(c, item.DeptId); err != nil {
				failNum++
				failMsg += "<br/>" + item.UserName + ":" + err.Error()
				continue
			}

			_ = utils.CopyStruct(&sysUser, &item)
			if item.Status == consts2.U_DISABLE_LABEL {
				sysUser.Status = consts2.U_DISABLE
			} else {
				sysUser.Status = consts2.U_NORMAL
			}
			if item.Sex == consts2.U_Sex_Male_Label {
				sysUser.Sex.String = consts2.U_Sex_Male
			} else if item.Sex == consts2.U_Sex_Female_Label {
				sysUser.Sex.String = consts2.U_Sex_Female
			} else {
				sysUser.Sex.String = consts2.U_Sex_Secret
			}
			sysUser.DeptId = &item.DeptId
			sysUser.UpdatedBy = operUsername
			result := base.BaseDb.Updates(&sysUser)
			if result.Error != nil {
				failNum++
				failMsg += "<br/>" + item.UserName + ":" + result.Error.Error()
				continue
			}
			successNum++
			successMsg += "<br/>" + item.UserName + ": 导入成功"
		} else {
			failNum++
			failMsg += "<br/>" + item.UserName + ": 已存在"
		}
	}
	if failNum > 0 {
		return "", moerrors.NewValidateError(consts.FilesUploadFailCode, fmt.Sprintf("导入失败 %d 条，成功 %d 条 %s", failNum, successNum, failMsg))
	}
	return fmt.Sprintf("导入成功 %d 条 %s", successNum, successMsg), nil
}

func (s *SysUserService) dataItemsFromImportUser(fileHeader *multipart.FileHeader) (*[]s1.UserImportDataItemReq, error) {
	file, err := fileHeader.Open()
	if err != nil {
		return nil, err
	}
	defer func() { _ = file.Close() }()
	importExcelFile := utils.NewImportExcelFile()
	importItemsReq := make([]s1.UserImportDataItemReq, 0)
	err = importExcelFile.ImportFromReader(file, &importItemsReq)
	return &importItemsReq, err
}
